﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using Microsoft.Surface.Presentation;
using System.Windows.Data;
using Microsoft.Surface.Presentation.Controls;
using System.ComponentModel;
using System.Windows.Media;
using Microsoft.Surface.Presentation.Controls.Primitives;
using System.Windows.Media.Animation;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace WPFMitsuControlsv2
{
    [TemplatePart(Name = BookItem.ElementBorder, Type = typeof(Border))]
    [TemplatePart(Name = BookItem.ElementInnerGrid, Type = typeof(Grid))]
    [TemplatePart(Name = BookItem.ElementContentPresenter, Type = typeof(ContentPresenter))]
    [TemplatePart(Name = BookItem.ElementDeletePopup, Type = typeof(SurfacePopup))]
    [TemplatePart(Name = BookItem.ElementDeleteButton, Type = typeof(SurfaceButton))]
    public class BookItem : SurfaceHeaderedContentControl
    {

        private const string ElementBorder = "PART_Border";
        private const string ElementInnerGrid = "PART_InnerGrid";
        private const string ElementContentPresenter = "PART_ContentPresenter";
        private const string ElementDeletePopup = "PART_DeletePopup";
        private const string ElementDeleteButton = "PART_DeleteButton";

        private Border _border;
        private Grid _innerGrid;
        private SurfaceTextBox _textbox;
        private ContentPresenter _contentPresenter;
        private SurfacePopup _deletePopup;
        private SurfaceButton _deleteButton;

        private bool _contactWasDown;
        private bool _contactWasTapGesture;
        private bool _isEditing;

        static BookItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BookItem), new FrameworkPropertyMetadata(typeof(BookItem)));
        }

        public override void OnApplyTemplate()
        {
            if (_border != null)
                Contacts.RemoveContactDownHandler(_border, OnContactDown);

            _border = GetTemplateChild(BookItem.ElementBorder) as Border;

            _innerGrid = GetTemplateChild(BookItem.ElementInnerGrid) as Grid;
            _contentPresenter = GetTemplateChild(BookItem.ElementContentPresenter) as ContentPresenter;
            _deletePopup = GetTemplateChild(BookItem.ElementDeletePopup) as SurfacePopup;
            _deleteButton = GetTemplateChild(BookItem.ElementDeleteButton) as SurfaceButton;

            if (_border != null)
                Contacts.AddContactDownHandler(_border, OnContactDown);

            if (ParentScrollViewer != null && ParentScrollViewer.IsPanningEnabled)
            {
                ParentScrollViewer.ContactTapGesture += new ContactEventHandler(OnScrollViewerContactTapGesture);
                ParentScrollViewer.LostContactCapture += new ContactEventHandler(OnScrollViewerLostContactCapture);
                ParentScrollViewer.ContactHoldGesture += new ContactEventHandler(OnScrollViewerLostContactHoldGesture);
            }
            else if (_border != null)
            {
                Contacts.AddContactTapGestureHandler(_border, OnContactTapGesture);
            }

            base.OnApplyTemplate();
        }

        protected Book BookParent
        {
            get
            {
                return (ItemsControl.ItemsControlFromItemContainer(this) as Book);
            }
        }

        public int PageIndex
        {
            get
            {
                var bp = BookParent;
                if (bp != null)
                    return bp.ItemContainerGenerator.IndexFromContainer(this);
                else
                    return -1;
            }
        }

        private SurfaceScrollViewer ParentScrollViewer
        {
            get
            {
                return WPFHelper.FindVisualParent<SurfaceScrollViewer>(this);
            }
        }

        #region Public properties

        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            internal set { SetValue(IsSelectedProperty, value); }
        }

        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(BookItem), new UIPropertyMetadata(false, OnIsSectedChanged));

        public Dock BookmarksPlacement
        {
            get
            {
                return (Dock)base.GetValue(BookmarksPlacementProperty);
            }
        }

        private static readonly DependencyPropertyKey BookmarksPlacementPropertyKey = DependencyProperty.RegisterReadOnly("BookmarksPlacement",
            typeof(Dock), typeof(BookItem), new FrameworkPropertyMetadata(Dock.Top, null, new CoerceValueCallback(CoerceBookmarksPlacement)));
        public static readonly DependencyProperty BookmarksPlacementProperty = BookmarksPlacementPropertyKey.DependencyProperty;

        public Visibility BookmarksVisibility
        {
            get
            {
                return (Visibility)base.GetValue(BookmarksVisibilityProperty);
            }
        }

        private static readonly DependencyPropertyKey BookmarksVisibilityPropertyKey = DependencyProperty.RegisterReadOnly("BookmarksVisibility",
            typeof(Visibility), typeof(BookItem), new FrameworkPropertyMetadata(Visibility.Visible, null, new CoerceValueCallback(CoerceBookmarksVisibility)));
        public static readonly DependencyProperty BookmarksVisibilityProperty = BookmarksVisibilityPropertyKey.DependencyProperty;

        #endregion

        private static object CoerceBookmarksPlacement(DependencyObject d, object value)
        {
            Book bookParent = ((BookItem)d).BookParent;
            if (bookParent == null)
                return value;
            return bookParent.BookmarksPlacement;
        }

        private static object CoerceBookmarksVisibility(DependencyObject d, object value)
        {
            Book bookParent = ((BookItem)d).BookParent;
            if (bookParent == null)
                return value;
            return bookParent.BookmarksVisibility;
        }

        private static void OnIsSectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var bookItem = d as BookItem;

            if (d == null)
                return;

            if (!(bool)e.NewValue)
                bookItem.UnFocus();
        }

        private void OnContactDown(object sender, ContactEventArgs e)
        {
            _contactWasDown = true;
            _contactWasTapGesture = false;
        }

        private void OnScrollViewerContactTapGesture(object sender, ContactEventArgs e)
        {
            _contactWasTapGesture = true;
        }

        private void OnScrollViewerLostContactCapture(object sender, ContactEventArgs e)
        {
            if (_border != null && _contactWasDown && _contactWasTapGesture)
            {
                HandleTap();
            }

            _contactWasDown = false;
            _contactWasTapGesture = false;
        }

        private void OnScrollViewerLostContactHoldGesture(object sender, ContactEventArgs e)
        {
            if (_border != null && _contactWasDown)
            {
                HandleDeletion();
            }
        }

        protected virtual void HandleTap()
        {
            this.Focus();

            if (IsSelected && _innerGrid != null && !_isEditing)
                BeginEdit();
            else
                NavigateToThisBookItem();
        }

        private void OnContactTapGesture(object sender, ContactEventArgs e)
        {
            HandleTap();
        }

        protected virtual void HandleDeletion()
        {
            if (_deletePopup != null && _deleteButton != null)
            {
                _deletePopup.IsOpen = true;
                var sb = this.FindResource("PoubelleStoryboard") as Storyboard;

                if (sb != null)
                    sb.Begin(_deletePopup, true);

                _deleteButton.Click += (s, e) =>
                {
                    //StartDeletionAnimation(() =>
                    //{
                        this.Header = null;
                        _deletePopup.IsOpen = false;
                    //});
                };

            }
        }

        private void StartDeletionAnimation(Action completedCallBack)
        {
            if (_border != null)
            {

                var couvercleRectangle = _deleteButton.FindName("rectangle") as Rectangle;
                if (couvercleRectangle == null)
                    return;

                Storyboard sb = new Storyboard();

                // create a rectangle with visual brush in a popup which will move into the trash bin

                var dpi = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;

                //var b = VisualTreeHelper.GetDescendantBounds(_border);
                var t = VisualTreeHelper.GetTransform(this);

                RenderTargetBitmap bmp = new RenderTargetBitmap((int)_border.ActualWidth, (int)_border.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                bmp.Render(this._border);
                
                var diagonalLength = Math.Sqrt(
                    this._border.ActualHeight * this._border.ActualHeight +
                    this._border.ActualWidth * this._border.ActualWidth);

                Border borderCopy = new Border()
                {
                    Background = new ImageBrush(bmp) { Stretch = Stretch.Fill },
                    RenderTransform = new TransformGroup() { Children = { new RotateTransform(), new ScaleTransform() } },
                    Width = this._border.ActualWidth,
                    Height = this._border.ActualHeight,
                    RenderTransformOrigin = new Point(0.5, 0.5),
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center
                };

                SurfacePopup popup = new SurfacePopup()
                {
                    Child = new Border()
                    {
                        Child = borderCopy,
                        Width = diagonalLength,
                        Height = diagonalLength,
                    },
                    AllowsTransparency = true,
                    Placement = PlacementMode.Relative,
                    PlacementTarget = this._border,
                    IsOpen = true,
                    StaysOpen = true,
                    Width = diagonalLength,
                    Height = diagonalLength,
                };

                var startPoint = new Point(0, 0);
                var endPoint = couvercleRectangle.TranslatePoint(
                        new Point(
                            couvercleRectangle.ActualWidth / 2 - (diagonalLength - _border.ActualWidth) - _border.ActualWidth / 2,
                            couvercleRectangle.ActualHeight - (diagonalLength - _border.ActualHeight)
                        ),
                    _border);

                var animationDuration = new Duration(TimeSpan.FromMilliseconds(3000));

                BezierSegment bs = new BezierSegment(
                    startPoint,
                    new Point(endPoint.X + _border.ActualWidth * 3, endPoint.Y - _border.ActualHeight), 
                    endPoint, true);

                PathGeometry path = new PathGeometry();
                PathFigure figure = new PathFigure();
                figure.StartPoint = startPoint;
                figure.Segments.Add(bs);
                figure.IsClosed = false;
                path.Figures.Add(figure);

                PointAnimationUsingPath pointAnim =
                    new PointAnimationUsingPath();
                pointAnim.PathGeometry = path;
                pointAnim.Duration = animationDuration;
                //pointAnim.AccelerationRatio = 0.6;

                DoubleAnimationUsingPath animX = new DoubleAnimationUsingPath()
                {
                    Source = PathAnimationSource.X,
                    PathGeometry = path,
                    Duration = animationDuration,
                    AccelerationRatio = .2,
                };

                DoubleAnimationUsingPath animY = animX.Clone();
                animY.Source = PathAnimationSource.Y;

                DoubleAnimation angle = new DoubleAnimation(-800, animationDuration) { AccelerationRatio = .8 };
                DoubleAnimation scaleX = new DoubleAnimation(0, animationDuration) { AccelerationRatio = .2 };
                DoubleAnimation scaleY = new DoubleAnimation(0, animationDuration) { AccelerationRatio = .2 };

                //DoubleAnimation angleTrashOpening = new DoubleAnimation(-30, animationDuration); //{ AccelerationRatio = .6 };
                //DoubleAnimation angleTrashClosing = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(200)))
                //{
                //    BeginTime = animationDuration.TimeSpan,
                //    //AccelerationRatio = .6
                //};
                //DoubleAnimation couvercleY = new DoubleAnimation(-5, animationDuration);

                sb.Children.Add(animX);
                sb.Children.Add(animY);
                sb.Children.Add(angle);
                sb.Children.Add(scaleX);
                sb.Children.Add(scaleY);
                //sb.Children.Add(angleTrashOpening);
                //sb.Children.Add(angleTrashClosing);
                //sb.Children.Add(couvercleY);

                Storyboard.SetTargetProperty(animX, new PropertyPath("HorizontalOffset"));
                Storyboard.SetTargetProperty(animY, new PropertyPath("VerticalOffset"));
                Storyboard.SetTarget(angle, borderCopy);
                Storyboard.SetTargetProperty(angle, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
                Storyboard.SetTarget(scaleX, borderCopy);
                Storyboard.SetTargetProperty(scaleX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)"));
                Storyboard.SetTarget(scaleY, borderCopy);
                Storyboard.SetTargetProperty(scaleY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)"));

                //Storyboard.SetTarget(angleTrashOpening, couvercleRectangle);
                //Storyboard.SetTargetProperty(angleTrashOpening, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"));
                //Storyboard.SetTarget(angleTrashClosing, couvercleRectangle);
                //Storyboard.SetTargetProperty(angleTrashClosing, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"));
                //Storyboard.SetTarget(couvercleY, couvercleRectangle);
                //Storyboard.SetTargetProperty(couvercleY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"));

                _innerGrid.Children.Add(popup);

                var poubelleSB = this.FindResource("PoubelleStoryboard") as Storyboard;
                if (poubelleSB != null && poubelleSB.GetCurrentState(_deletePopup) == ClockState.Active)
                    poubelleSB.Stop(_deletePopup);

                sb.Completed += (s, e) =>
                    {
                        _border.Visibility = Visibility.Visible;
                        _innerGrid.Children.Remove(popup);
                        completedCallBack();
                    };

                sb.Begin(popup);

                _border.Visibility = Visibility.Hidden;

            }

        }

        public void NavigateToThisBookItem()
        {
            BookParent.AnimateToIndex(BookParent.ItemContainerGenerator.IndexFromContainer(this));
        }

        public virtual void BeginEdit()
        {
            this.Focus();

            _isEditing = true;

            // toggle edit mode
            var headerStr = Header as string;

            if (headerStr != null && _innerGrid != null)
            {
                _textbox = new SurfaceTextBox();

                Binding b = new Binding("Header");
                b.Source = this;
                b.Mode = BindingMode.TwoWay;

                _textbox.SetBinding(TextBox.TextProperty, b);
                _innerGrid.Children.Add(_textbox);

                _textbox.LostKeyboardFocus += (s, ee) =>
                {
                    UnFocus();
                };

                _textbox.KeyDown += (s, ee) =>
                {
                    if (ee.Key == System.Windows.Input.Key.Enter)
                        UnFocus();
                };

                if (_contentPresenter != null)
                    _contentPresenter.Visibility = Visibility.Hidden;
                _textbox.Focus();

            }
        }

        protected virtual void UnFocus()
        {
            RemoveTB();
        }

        private void RemoveTB()
        {
            if (_textbox != null)
            {
                _innerGrid.Children.Remove(_textbox);
                _textbox = null;
            }
            if (_contentPresenter != null)
                _contentPresenter.Visibility = Visibility.Visible;

            _isEditing = false;
        }

    }
}
